#!/usr/bin/python

import copy
import gobject
import gtk
import gtk.glade
import os
import pygtk
import random
import rsvg
import sys
import time

import game 
import data
import pixmap_loader
from ui.ui import UI


class Schrenckii:
    """Schrenckii GTK Interface"""

    def __init__(self):
        self.num = 0

        self.gs = game.GameState()

        self.ui = UI()

        self.gc = self.ui.draw_area_game.get_style().black_gc
        self.kh_id = None
        self.timeout = None
        self.score_anim_h = []

        # Attach handlers to menu items
        self.ui.get_widget("menuitemNew").connect("activate",
            self.new_game)

        self.ui.get_widget("menuitemQuit").connect("activate",
            gtk.main_quit)

        self.ui.get_widget("menuitemAbout").connect("activate",
            lambda w: self.show_dialog(self.ui.about))

        self.ui.get_widget("menuitemPreferences").connect("activate",
            lambda w: self.show_dialog(self.ui.preferences))

        self.ui.about.window.connect("response", self.on_dialog_response)

        self.ui.preferences.window.connect("response", self.on_dialog_response)

        if(self.ui.window):
            self.ui.window.connect("destroy", gtk.main_quit)
        
        dir = self.gs.settings.value("theme/theme")
        
        self.pixmap_loader = pixmap_loader.PixmapLoader(dir,
            self.ui.draw_area_game.window, self.gc)

        # Reload the pixmaps with the new window size
        self.pixmap_loader.reload_pixmaps(*self.ui.draw_area_game.window.get_size())
        
        # Start the game!
        self.new_game()

        # Connect expose event handlers
        self.ui.draw_area_game.connect("expose_event", self.expose)

        # Connect configure event handlers
        self.ui.draw_area_game.connect("configure_event", self.configure)

        self.get_controls()

    
    def new_game(self, widget=None):
        self.gs.new()

        self.pixmap_loader.gs = self.gs

        self.lastTick = time.time()

        # Disconnect any previous keypress and timeout event handlers
        if self.kh_id is not None:
            self.ui.window.disconnect(self.kh_id)

        if self.timeout is not None:
            gobject.source_remove(self.timeout)

        # Connect keypress and timeout event handlers
        self.kh_id = self.ui.window.connect("key_press_event", self.keyhandler)
        self.timeout = gobject.timeout_add(self.time_calc(), self.timed_move)

        self.total_refresh()


    def redraw(self, x, y, width, height):
        rect = gtk.gdk.Rectangle(x, y, width, height)
        self.ui.draw_area_game.window.invalidate_rect(rect)
        

    def expose(self, widget, event):
        rect = event.area

        # Check for game over
        if self.gs.gameover and self.timeout != None and self.kh_id != None:
            gobject.source_remove(self.timeout)
            self.ui.window.disconnect(self.kh_id)
            self.timeout = None
            self.kh_id = None
        
        widget.window.draw_drawable(self.gc, self.pixmap_loader.state_pixmap,
            rect.x, rect.y, rect.x, rect.y, rect.width, rect.height)
       
        return False


    def configure(self, widget, event):
        """Stuff to do when the window is resized."""

        # If the game is not already paused, pause it. This could take a while.
        previouslypaused = self.gs.paused
        if not previouslypaused:
            self.pause()

        print str(self.num) + " configured"
        self.num = self.num + 1

        # Reload the pixmaps with the new window size
        self.pixmap_loader.reload_pixmaps(event.width, event.height)

        if not previouslypaused:
            self.unpause()

        self.total_refresh()


    def total_refresh(self):
        """This needs to be called after pixmap_loader.reload_pixmaps to get 
        everything back up to par."""

        # Recreate board and game pixmaps
        self.pixmap_loader.draw_board_pixmap()
        self.pixmap_loader.draw_game_pixmap()

        # Refresh the various areas of the state pixmap
        self.pixmap_loader.refresh_state("game")
        self.pixmap_loader.refresh_state("next")
        self.pixmap_loader.refresh_state("hold")
        self.pixmap_loader.refresh_state("titles")

        self.ui.draw_area_game.queue_draw()


    def keyhandler(self, widget, event):
        areas = ["game"]

        #print str(event.keyval)
        #print gtk.gdk.keyval_name(event.keyval)

        if not self.gs.paused:

            if event.keyval == self.controls["rotate_counterclockwise"]:
                self.gs.make_move("RotateCCW")

            elif event.keyval == self.controls["rotate_clockwise"]:
                self.gs.make_move("RotateCW")

            elif event.keyval == self.controls["down"]:
                result = self.gs.make_move("Down")
                if result is not None:
                    self.pixmap_loader.draw_board_pixmap()
                    areas.append("next")
                    self.start_score_anim(*result)

            elif event.keyval == self.controls["right"]:
                self.gs.make_move("Right")

            elif event.keyval == self.controls["left"]:
                self.gs.make_move("Left")

            elif event.keyval == self.controls["hold"]:
                if self.gs.hold_piece():
                    areas.append("hold")

            elif event.keyval == self.controls["hard_drop"]:
                result = self.gs.hard_drop()
                self.pixmap_loader.draw_board_pixmap()
                self.start_score_anim(*result)
                areas.append("next")

            elif event.keyval == self.controls["pause"]:
                self.pause()

            else:
                return False

        else:
            if event.keyval == self.controls["pause"]:
                self.unpause()

            else:
                return False

        self.pixmap_loader.draw_game_pixmap()

        for area in areas:
            self.pixmap_loader.refresh_state(area)

        self.ui.draw_area_game.queue_draw()

        return False


    def pause(self):
        if not self.gs.gameover and not self.gs.paused:
            currenttime = time.time()
            timetonext = float(self.time_calc())/1000

            self.gs.paused = True

            # Calculate the time that the next timeout should wait before
            # moving the piece down. Don't want to start the timer from
            # the start again.

            self.pTimeout = self.lastTick + timetonext - currenttime

            self.pTimeout = int(self.pTimeout*1000)

            if self.pTimeout < 0:
                self.pTimeout = 0

            gobject.source_remove(self.timeout)

            self.pixmap_loader.draw_game_pixmap()
            self.pixmap_loader.refresh_state("game")
            self.ui.draw_area_game.queue_draw()


    def unpause(self):
        if not self.gs.gameover and self.gs.paused:
            self.gs.paused = False

            # Restart the timer, but with the correct initial time
            self.timeout = gobject.timeout_add(self.pTimeout,self.timed_move)


    def timed_move(self):
        # Save the time that the piece was moved down for use with pausing
        self.lastTick = time.time()

        areas = ["game"]

        result = self.gs.make_move("Down")
        if result is not None:
            self.pixmap_loader.draw_board_pixmap()
            areas.append("next")
            self.start_score_anim(*result)

        self.pixmap_loader.draw_game_pixmap()

        for area in areas:
            self.pixmap_loader.refresh_state(area)

        self.ui.draw_area_game.queue_draw()
        
        if self.timeout is not None:
            gobject.source_remove(self.timeout)
            self.timeout = gobject.timeout_add(self.time_calc(),
                self.timed_move)

        return True


    def time_calc(self):
        t = 1000

        for i in range(0, self.gs.level - 1):
            t = t * 4 / 5

        return t

    
    def start_score_anim(self, x, score):
        score_anim = pixmap_loader.ScoreAnim(x, data.board_width,
            self.pixmap_loader.psize, score)
        self.pixmap_loader.anims.append(score_anim)
        gobject.timeout_add(30, self.animate_score, score_anim)


    def animate_score(self, score_anim):
        result = score_anim.animate()
        
        if not result:
            self.pixmap_loader.anims.remove(score_anim)

        self.pixmap_loader.refresh_state("game")
        self.ui.draw_area_game.queue_draw()
        
        return result


    def show_dialog(self, dialog):
        self.pause()
        dialog.window.show()


    def on_dialog_response(self, window, rid):
        # Update based on any changes made to the preferences (e.g. theme)
        if window == self.ui.preferences.window:
            if rid == gtk.RESPONSE_OK or rid == gtk.RESPONSE_APPLY:
                self.pixmap_loader.new_theme()
                self.total_refresh()
                self.gs.random_colours =\
                    self.gs.settings.value("gameplay/random_colours")

                self.get_controls()

        if rid == gtk.RESPONSE_OK or rid == gtk.RESPONSE_CANCEL:
            self.unpause()


    def get_controls(self):
        self.controls = {}
        for control in self.gs.settings.controls:
            self.controls[control] =\
                self.gs.settings.value("control/" + control)


def colour_to_rgb(colour):
    if colour == "Red": return (1,0,0)
    elif colour == "Green": return (0,1,0)
    elif colour == "Blue": return (0,0,1)
    elif colour == "White": return (1,1,1)
    elif colour == "Purple": return (1,0,1)
    elif colour == "Orange": return (1,0.5,0)
    else: return (1,1,0)


random.seed()

if __name__ == "__main__":
    schrenckii = Schrenckii()
    schrenckii.ui.window.show_all()
    gtk.main()

